#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <regex.h>
#include <curl/curl.h>
#include "cJSON.h"

/* 正则式
  ; \"([^\"]*)\",
 */
struct geoip_data
{
  char ip[256];
  char country[256];
  //char area[256];
  char region[256];
  char city[256];
  //char county[256];
  char isp[256];
  char country_id[256];
  //char area_id[256];
  char region_id[256];
  char city_id[256];
  //char county_id[256];
  char isp_id[256];
};

struct  geoip{
  size_t curl_size;
  char *curl_ptr;
  char ip[32];
  cJSON *_data;
  struct geoip_data data;
};

void init_geoip(struct geoip *g) {
  g->curl_size = 0;
  g->curl_ptr = malloc(g->curl_size+1);
  if (g->curl_ptr == NULL) {
    fprintf(stderr, "malloc() failed\n");
    exit(EXIT_FAILURE);
  }
  g->curl_ptr[0] = '\0';

  g->_data = NULL;
}

void deinit_geoip(struct geoip *g)
{
  free(g->curl_ptr);
  g->curl_ptr = NULL;
}

size_t writefunc(void *ptr, size_t size, size_t nmemb, struct geoip *g)
{
  size_t new_size = g->curl_size + size*nmemb;
  g->curl_ptr = realloc(g->curl_ptr, new_size+1);
  if (g->curl_ptr == NULL) {
    fprintf(stderr, "realloc() failed\n");
    exit(EXIT_FAILURE);
  }
  memcpy(g->curl_ptr+g->curl_size, ptr, size*nmemb);
  g->curl_ptr[new_size] = '\0';
  g->curl_size = new_size;
  //printf("[DEBUG] server reply %d bytes.\n", (int)(size*nmemb));
  return size*nmemb;
}

void taobao_get_ip(struct geoip *g)
{
  CURL *curl;
  CURLcode res;
  curl = curl_easy_init();
  if(curl) {
    init_geoip(g);

    curl_easy_setopt(curl, CURLOPT_URL, "https://www.taobao.com/help/getip.php");
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, g);
    res = curl_easy_perform(curl);

    /* 正则表达式, 获取双引号之间的内容
      \"(.*?)\"
      或者
      \"([^\"]*)\"
     */
    char *pattern = "\"(.*?)\"";
    regex_t regex;
    int regexInit = regcomp( &regex, pattern, REG_EXTENDED );
    if( regexInit != 0)
    {
      fprintf(stderr, "Compile regex failed\n" );
    }else{
      regmatch_t pmatch[1];
      int reti = regexec( &regex, g->curl_ptr, 1, pmatch, 0 );
      if( REG_NOERROR != reti ){
          //Error print: match failed! 
        fprintf(stderr, "match failed!\n");
      }
      else{
        int len = pmatch[0].rm_eo-pmatch[0].rm_so;
        if(len){
          //去掉ip信息首位的2个双引号"xxx.xxx.xxx.xxx"
          memcpy(g->ip, g->curl_ptr+pmatch[0].rm_so +1, len-2);
          //printf("g->ip: %s\n", g->ip);
        }
      }
      regfree( &regex );
    }

    deinit_geoip(g);
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}

void taobao_get_geo(struct geoip *g)
{
  CURL *curl;
  CURLcode res;
  curl = curl_easy_init();
  if(curl) {
    init_geoip(g);
    char dest[256] = "http://ip.taobao.com/service/getIpInfo.php?ip=";
    curl_easy_setopt(curl, CURLOPT_URL, strcat(dest, g->ip));
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, g);
    res = curl_easy_perform(curl);

    /* always cleanup */
    curl_easy_cleanup(curl);
  }

  cJSON* root = cJSON_Parse(g->curl_ptr);
  g->_data = cJSON_GetObjectItemCaseSensitive(root, "data");
  strcpy( g->data.ip, cJSON_GetObjectItemCaseSensitive(g->_data, "ip")->valuestring );
  strcpy( g->data.country, cJSON_GetObjectItemCaseSensitive(g->_data, "country")->valuestring );
  strcpy( g->data.region, cJSON_GetObjectItemCaseSensitive(g->_data, "region")->valuestring );
  strcpy( g->data.city, cJSON_GetObjectItemCaseSensitive(g->_data, "city")->valuestring );
  strcpy( g->data.isp, cJSON_GetObjectItemCaseSensitive(g->_data, "isp")->valuestring );
  strcpy( g->data.country_id, cJSON_GetObjectItemCaseSensitive(g->_data, "country_id")->valuestring );
  strcpy( g->data.region_id, cJSON_GetObjectItemCaseSensitive(g->_data, "region_id")->valuestring );
  strcpy( g->data.city_id, cJSON_GetObjectItemCaseSensitive(g->_data, "city_id")->valuestring );
  strcpy( g->data.isp_id, cJSON_GetObjectItemCaseSensitive(g->_data, "isp_id")->valuestring );

  deinit_geoip(g);
}

void taobao_geo_print(struct geoip *g)
{
  printf("ip: %s\n", g->data.ip);
  printf("country: %s\n", g->data.country);
  printf("region: %s\n", g->data.region);
  printf("city: %s\n", g->data.city);
  printf("isp: %s\n", g->data.isp);
  printf("country_id: %s\n", g->data.country_id);
  printf("region_id: %s\n", g->data.region_id);
  printf("city_id: %s\n", g->data.city_id);
  printf("isp_id: %s\n", g->data.isp_id);
}

int main(int argc, char* argv[])
{
  struct geoip g;
  taobao_get_ip(&g);
  taobao_get_geo(&g);
  taobao_geo_print(&g);

  return 0;
}
